﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 战棋模拟器
{
    class Board
    {//数据结构部分
        public Pool upPool;
        public Pool downPool;
        public Pool nowattacking;//当前进攻方
        public int windwrath = 0;//当前风怒值
        public bool Debug;
        public bool DeathWing = false;
        public Queue<Minion> deadQ = new Queue<Minion>();



        //不添加随从的初始化
        public Board(bool ifdebug)
        {
            downPool = new Pool();
            upPool = new Pool();
            downPool.direction = false;
            upPool.direction = true;
            downPool.board = this;
            upPool.board = this;
            downPool.next = upPool;
            upPool.next = downPool;
            Debug = ifdebug;
        }



        //用来构造已经生成好pool的游戏场景
        public Board(bool ifdebug, Pool d, Pool u)
        {
            downPool = d;
            downPool.board = this;
            d.direction = false;
            u.direction = true;
            upPool = u;
            upPool.board = this;
            downPool.next = upPool;
            upPool.next = downPool;
            Debug = ifdebug;
        }



        //执行攻击,风怒随从不是在这个函数中判定,0攻随从认为不会使用此函数。
        public bool Attack(Minion attacker, Minion attackee)
        {
            //if (attacker == null || attackee == null)
            //    return false;
            if (Debug)
                Console.WriteLine("{0}第{1}个随从{4}攻击了{2}第{3}个随从{5}",
                    attacker.pool.direction ? "上方" : "下方",
                    attacker.pool.current,
                    attackee.pool.direction ? "上方" : "下方",
                    attackee.Place,
                    " " + attacker.Name + " ",
                    " " + attackee.Name + " ");
            //if (attacker.Attack == 0)
            //    return false;
            attacker.Doattack(attackee);
            //attackee.Getattacked(attacker);
            return true;
        }



        //结算在此轮中应当死亡的随从(相当于对于同时发生的事情的结算，执行所有随从受伤，之后所有随从死亡的效果)：
        public void Reap()
        {
            while(deadQ.Count>0)
            {
                Minion m = deadQ.Dequeue();
                if (!m.alive)
                    continue;
                m.Die();
            }
        }

   

        //判断是否结束
        public bool Isover()
        {
            int L = downPool.Check();
            int U = upPool.Check();
            if (L >= 0 && U >= 0 && L + U > 0)
                return false;
            if (Debug)
                Console.WriteLine("\n游戏结束。\n\n");
            return true;
        }


        //演化,直至游戏结束
        public void Evolve()
        {
            //if (nowattacking == null)
            //    nowattacking = DirDetermine()?upPool:downPool;
            while (!Isover())//判断是否结束   
            {
                if (nowattacking.Check() == 0)
                {
                    nowattacking.current = -1;
                    nowattacking = nowattacking.next;
                    continue;
                }
                if (windwrath == 0)
                {
                    nowattacking.CurrentAddOne();
                    windwrath = 1;
                    if (nowattacking.places[nowattacking.current].Skills[1])
                        windwrath = 2;
                    else if (nowattacking.places[nowattacking.current].Skills[5])
                        windwrath = 4;
                }
                Minion atter = nowattacking.places[nowattacking.current >= 0 ? nowattacking.current : 0];
                if (atter.Name != "扎普斯里维克" && atter.Name != "扎普斯里维克_金色")
                    Attack(atter, nowattacking.next.GetOpponent());
                else
                    Attack(atter, nowattacking.next.GetOpponent(1));
                Reap();
                
                windwrath--;
                if (windwrath == 0 || atter.Health < 1)
                {
                    nowattacking = nowattacking.next;
                    windwrath = 0;
                }
                if (Debug)
                {
                    Showboard();
                    if(!Isover())
                        ShowDetail();
                }
            }
        }



        //执行算法
        public void Execute(bool direction)
        {
            nowattacking = direction ? upPool : downPool;
            if (Debug)
            {
                Showboard();
                ShowDetail();
            }
            upPool.Initialize();
            downPool.Initialize();
            Start(direction);
            
            Evolve();
            if (Debug)
                Output();
        }



        //输出结果
        public void Output()
        {
            int i = GetOutput();
            switch(i)
            {
                case 1:
                    Console.WriteLine("上方胜利");
                    break;
                case -1:
                    Console.WriteLine("下方胜利");
                    break;
                case 0:
                    Console.WriteLine("平局");
                    break;
            }
            Console.WriteLine("共对英雄造成{0}点随从伤害", Math.Abs(MinionDamage()));
        }



        //打扫战场，评判胜负
        public int GetOutput()
        {
            int L = downPool.Check();
            int U = upPool.Check();
            if (L + U == 2)
                throw new Exception("还没打完");
            if (L == U)
                return 0;
            return L > U ? -1 : 1;
        }



        //格式输出棋盘
        public void Showboard()
        {
            Console.WriteLine("\n当前棋盘显示如下:");
            Console.WriteLine("上方棋盘：");
            for(int i = 0;i<7;i++)
            {
                if (upPool.places[i] == null)
                    break;
                Console.Write("第{0}位：{1}，{2}/{3} {4}{5}{6}{7}{8}{9}   ",
                    i,
                    upPool.places[i].Name,
                    upPool.places[i].Attack,
                    upPool.places[i].Health,
                    upPool.places[i].Skills[0] ? "剧毒 " : "",
                    upPool.places[i].Skills[2] ? "嘲讽 " : "",
                    upPool.places[i].Skills[3] ? "圣盾 " : "",
                    upPool.places[i].Skills[5] ? "超级风怒" : "",
                    upPool.places[i].Skills[1] ? "风怒" : "",
                    upPool.places[i].Skills[4] ? "复生" : "");
            }
            Console.WriteLine("\n下方棋盘：");
            for (int i = 0; i < 7; i++)
            {
                if (downPool.places[i] == null)
                    break;
                Console.Write("第{0}位：{1}，{2}/{3} {4}{5}{6}{7}{8}   ",
                    i, 
                    downPool.places[i].Name,
                    downPool.places[i].Attack,
                    downPool.places[i].Health,
                    downPool.places[i].Skills[0] ? "剧毒 " : "",
                    downPool.places[i].Skills[2] ? "嘲讽 " : "",
                    downPool.places[i].Skills[3] ? "圣盾 " : "",
                    downPool.places[i].Skills[5] ? "超级风怒" : "",
                    downPool.places[i].Skills[1] ? "风怒" : "");
            }
            Console.WriteLine("\n");
        }



        //回合开始阶段触发的效果，目前仅有红色雏龙，结算顺序为先攻者先触发，然后轮流触发。不知道后续有更多随从后如何结算
        public void Start(bool direction)
        {
            if (Isover())
                return;
            if (Debug)
                Console.WriteLine("回合开始阶段：\n");
            Pool temp = direction ? upPool : downPool;
            int flag = 0;
            while(flag!=2)
            {
                flag = 2;
                foreach (Minion m in temp.places)
                {
                    if (m == null)
                        break;
                    if (m.startEffect>0)
                    {
                        m.Start();
                        m.startEffect --;
                        flag--;
                        break;
                    }
                }
                Reap();
                foreach (Minion n in temp.next.places)
                {
                    if (n == null)
                        break;
                    if (n.startEffect > 0)
                    {
                        n.Start();
                        n.startEffect--;
                        flag--;
                        break;
                    }
                }
                Reap();
            }
        }


        //共造成多少随从伤害
        public int MinionDamage()//应当在结束后调用
        {
            int r = 0;
            foreach(Minion m in upPool.places)
            {
                if (m == null)
                    break;
                r += m.Star;
            }
            foreach (Minion m in downPool.places)
            {
                if (m == null)
                    break;
                r -= m.Star;
            }
            return r;
        }


        //一定要检查是否为null
        public void Aoe(int n, List<Minion> victims)
        {
            if (n <= 0)
                return;
            List<Minion> ShieldedList = new List<Minion>();
            List<Minion> UnShieldedList = new List<Minion>();
            //先把所有有盾随从的盾手动扒掉，再触发他们的Shieldlost
            foreach (Minion m in victims)
            {
                if (m == null)
                    continue;
                if (m.Skills[3])
                {
                    ShieldedList.Add(m);
                    m.Skills[3] = false;
                }
                else//这个操作是为了防止钴制卫士搞事情，防止从左到右先补盾再破盾再补盾(一个没盾的钴制在两个安保中间的情况)
                {
                    UnShieldedList.Add(m);
                    m.Health -= n;//注意这里还没触发他们的getdamaged方法（因为这个方法和受伤事件的触发是耦合的）
                }
            }
            //然后再统一调用所有的函数：
            //因为有测试表明可以给正在死亡的随从套盾，所以先触发破盾函数再触发受伤函数
            //另一个理由则是可以有张牌龙人执行者可以先掉血再因为破盾加血再触发受伤效果就可以不死，而炉石里确实不会死
            //另一个理由则是胖头鱼可以破一次补一次
            foreach (var m in ShieldedList)
            {
                bool flag = m.Skills[3];
                m.ShieldLost();
                m.Skills[3] = flag;
            }
            foreach (var m in UnShieldedList)
                if(!m.Skills[3])
                    m.Getdamaged(0);
        }

        //复制方法获得一个一样的board
        public Board Copy()
        {
            Board duplicate;
            Pool u = upPool.Copy();
            Pool d = downPool.Copy();
            duplicate = new Board(false, d, u);
            duplicate.windwrath = windwrath;
            duplicate.nowattacking = (nowattacking==upPool)?u:d;
            duplicate.DeathWing = DeathWing;

            return duplicate;
        }

        //大数据实验
        public void Experiment()
        {
            double count = 10000;
            double dmg = 0;
            double downwin = 0, upwin = 0, draw = 0;
            for (double i = count; i > 0; i--)
            {
                Board b = Copy();
                if (Math.Abs(i - count) < 0.5)
                    b.Showboard();
                b.Execute(b.DirDetermine());
                int result = b.GetOutput();
                switch (result)
                {
                    case -1:
                        downwin++;
                        break;
                    case 0:
                        draw++;
                        break;
                    default:
                        upwin++;
                        break;
                }
                dmg += b.MinionDamage();
            }
            upwin /= count;
            downwin /= count;
            draw /= count;
            dmg /= count;
            Console.WriteLine("\n进行了{0}次实验，下方获胜概率为{1}，上方获胜概率为{2}，平局概率为{3}，平均用随从对英雄造成{4}点伤害",
                count,
                downwin,
                upwin,
                draw,
                Math.Abs(dmg));
        }


        //走势输出
        public void ShowDetail()
        {
            double count = 10000;
            double dmg = 0;
            double downwin = 0, upwin = 0, draw = 0;
            for (double i = count; i > 0; i--)
            {
                Board b = Copy();
                
                b.Evolve();
                int result = b.GetOutput();
                switch (result)
                {
                    case -1:
                        downwin++;
                        break;
                    case 0:
                        draw++;
                        break;
                    default:
                        upwin++;
                        break;
                }
                dmg += b.MinionDamage();
            }
            upwin /= count;
            downwin /= count;
            draw /= count;
            dmg /= count;
            Console.WriteLine("\n胜率情况转变为：\n下方获胜概率为{1}，上方获胜概率为{2}，平局概率为{3}，平均用随从对英雄造成{4}点伤害\n",
                count,
                downwin,
                upwin,
                draw,
                Math.Abs(dmg));
        }

        //返回一开始先攻击的方位
        public bool DirDetermine()
        {
            int uc = upPool.minionCount;
            int dc = downPool.minionCount;
            if (dc < uc)
                return true;
            if (uc < dc)
                return false;
            byte[] buffer = Guid.NewGuid().ToByteArray();
            int iSeed = BitConverter.ToInt32(buffer, 0);
            Random ran = new Random(iSeed);
            int RandKey = ran.Next(0, 2);
            if (RandKey == 0)
                return false;
            return true;
        }
    }
}
